Cryptext x64 File Format v1 -- FROZEN LAYOUT
=============================================

Status
------
The byte layout described here is frozen for format version 1. Once a writer
is enabled, an incompatible change requires a new format version. Reader-side
resource limits and the writer's default PBKDF2 cost may evolve without
changing the byte layout because the actual iteration count is stored per file.

Filename convention
-------------------
Plain file:       example.pdf
Encrypted file:   example.pdf.$#!
In-progress file: example.pdf.$#!.temp

The normal in-progress file is created beside the source and is hidden while
being written. The plaintext source is never modified in place.

Byte order and password encoding
--------------------------------
All stored integer fields are little-endian unless this document explicitly
says otherwise.

The password input to PBKDF2 is the exact sequence of UTF-16LE code units held
by SecureInput, excluding the terminating NUL. No Unicode normalization is
performed. A compatible non-Windows implementation must reproduce those exact
UTF-16LE bytes.

KDF and cipher
--------------
KDF ID 1:
  PBKDF2-HMAC-SHA-256
  salt length: 16 bytes
  output length: 32 bytes

Cipher ID 1:
  AES-256-GCM
  key length: 32 bytes
  nonce length: 12 bytes
  authentication tag length: 16 bytes

The reference writer default is 600,000 PBKDF2 iterations. This is a writer
policy, not a fixed constant of the format. The exact count is stored in every
header. Readers should apply sane local resource limits before accepting an
untrusted iteration count.

Fixed header -- 72 bytes
------------------------
Offset Size Meaning
------ ---- ---------------------------------------------------------------
0x00     8 Magic ASCII "CT64FILE"
0x08     2 Format version = 1
0x0A     2 Header size = 72
0x0C     4 Flags = 0 in v1
0x10     4 KDF ID = 1
0x14     4 Cipher ID = 1
0x18     4 PBKDF2 iteration count
0x1C     4 Plaintext data chunk size
0x20     8 Original plaintext file size
0x28     4 Metadata plaintext size = 48 in v1
0x2C     4 Reserved = 0
0x30    16 Random PBKDF2 salt
0x40     8 Random GCM nonce prefix

The reference writer uses 4 MiB data chunks. A v1 reader accepts power-of-two
chunk sizes from 64 KiB through 64 MiB. The stored value is authoritative.

Encrypted metadata plaintext -- 48 bytes
-----------------------------------------
Offset Size Meaning
------ ---- ---------------------------------------------------------------
0x00     4 Metadata version = 1
0x04     4 Metadata size = 48
0x08     8 Original creation FILETIME
0x10     8 Original last-write FILETIME
0x18     8 Original last-access FILETIME
0x20     4 Restorable FILE_ATTRIBUTE_* bits
0x24     4 Metadata flags = 0 in v1
0x28     8 Reserved = 0

Zone.Identifier is deliberately not preserved or restored. Other NTFS ADS are
not part of v1 and no lossless-ADS claim is made.

Record numbering and nonce derivation
-------------------------------------
Record 0 is the encrypted metadata record.
Data records are numbered 1, 2, 3, ... in file order.

Each record is one independent AES-GCM operation.

nonce[0..7]  = the 8-byte random nonce prefix from the fixed header
nonce[8..11] = record index encoded as uint32 BIG-ENDIAN

The 32-bit record index therefore limits v1 to at most 0xFFFFFFFF data records,
well beyond normal Windows file-size limits with the reference chunk size.

Authenticated Additional Data (AAD)
-----------------------------------
Every record authenticates an 80-byte AAD value:

AAD[0..71]  = exact 72 stored bytes of the fixed header
AAD[72..75] = record index encoded as uint32 little-endian
AAD[76..79] = record plaintext length encoded as uint32 little-endian

A change to any fixed-header byte therefore invalidates every record tag.
The index and length prevent silent record reordering or length substitution.

On-disk record layout
---------------------
There are no separate record headers.

Immediately after the 72-byte fixed header:

  metadata ciphertext (48 bytes)
  metadata GCM tag     (16 bytes)

Then, for each data chunk:

  data ciphertext      (same length as plaintext chunk)
  data GCM tag         (16 bytes)

The final data chunk may be shorter than the configured chunk size. An empty
source file has zero data records but still has the authenticated metadata
record.

Expected encrypted size
-----------------------
Let:
  H = 72
  M = 48
  T = 16
  P = original plaintext size
  C = chunk size
  N = ceil(P / C), with N = 0 when P = 0

Then:
  encrypted_size = H + M + T + P + (N * T)

A reader should reject truncation and unexpected trailing bytes rather than
silently accepting them.

Transactional write rule
------------------------
The planned writer uses:

  source.ext
      -> source.ext.$#!.temp  (CREATE_NEW, same directory, hidden)
      -> write complete authenticated file
      -> FlushFileBuffers
      -> close
      -> rename to source.ext.$#!
      -> restore intended timestamps/attributes
      -> only then optionally delete source.ext

The source is never encrypted in place. ERROR_DISK_FULL is handled even after
free-space preflight.

Recovery compatibility
----------------------
A future CryptextDecrypt.exe must need only the encrypted file and the real
password. It must not depend on the Explorer extension, registry vault, DPAPI
vault data, or installation state.

Legacy Cryptext 3.x is a separate read-only compatibility path and does not use
this format. New files are never written with legacy RC4/SHA-1.
